
/**
** \file       exec_cmdline.c
**
** \brief      This file contains the functions who handle the lexer
**
** \authors    Ben M'rad Hanna, Boillot Ulysse, De Oliveira Guillaume,
**             Laterem Hamza et Nguyen Viet Dung coded this file as a part
**             of the 42sh project.
**
** \version    0.8
**
** \data       26 November 2010
**
*/

#include "token.h"
#include "../exec_cmdline.h"

#define SIZE 23

static int              is_token(char           c)
{
  int                   i = 0;

  while (i < SIZE)
  {
    if (strncmp(&c, g_data->tab_token[i].id, 1) == 0)
      break;

    ++i;
  }

  if (i != SIZE)
    return (i);

  return (-1);
}

static char             *fill_first(char        *str,
                                    int         *i,
                                    char        *first)
{
  while (str[*i] != '\t' && str[*i] != ' ' && str[*i] != '\0'
         && is_token(str[*i]) == -1)
  {
    *i += 1;
    first = realloc(first, *i);
    first[*i - 1] = str[*i - 1];
  }

  return (first);
}

static char             *rep_token(char         *str,
                                   int          *i,
                                   char         *first)
{
  if (str[1] == '<')
  {
    if (str[2] == '-')
    {
      first = realloc(first, *i = 3);
      first[0] = '<';
      first[1] = '<';
      first[2] = '-';
    }
  }

  if (str[1] == '&' || str[1] == '|')
  {
    first = realloc(first, *i = 2);
    first[0] = str[0];
    first[1] = str[1];
  }

  return (first);
}

static char             *ambi_token(char       *str,
				    int        *i,
				    char       *first)
{
  if (str[0] == '<')
  {
    if (str[1] == '>' || str[1] == '&')
    {
      first = realloc(first, *i = 2);
      first[1] = str[1];
    }
  }
  if (str[0] == '>')
  {
    if (str[1] == '&' || str[1] == '|')
    {
      first = realloc(first, *i = 2);
      first[1] = str[1];
    }
  }

  if (str[1] == str[0])
    first = rep_token(str, i, first);

  return (first);
}

static char             *fn(int                 *i,
                            char                *first)
{
  *i += 1;
  first = realloc(first, *i);
  first[*i - 1] = '\0';

  return (first);
}

static s_lexer          *the_function(char      *str,
                                      char      *first,
                                      s_lexer   *new_lex,
                                      s_lexer   *lexer)
{
  for (int j = 0; j < SIZE; ++j)
  {
    if (strcmp(first, g_data->tab_token[j].id) == 0 || j == SIZE - 1)
    {
      lexer->token->type = g_data->tab_token[j].type;
      lexer->token->id = calloc(1, strlen(first) + 1);
      lexer->token->id = strcpy(lexer->token->id, first);
      new_lex = calloc(1, sizeof (s_lexer));
      new_lex->head = lexer->head;
      new_lex->token = calloc(1, sizeof (s_token));

      if (strcmp(str + strlen(first), "") == 0)
      {
        free(new_lex->token->id);
        free(new_lex->token);
        free(new_lex);
        new_lex = lexer->head;
        lexer->next = NULL;
      }
      else
        lexer->next = new_lex;

      break;
    }
  }

  return (new_lex);
}

static s_lexer          *aux(char               *first,
                             s_lexer            *lexer)
{
  free(first);
  return (lexer);
}

static char             **comment(char           *first,
                                  char           **str)
{
  if (strcmp(first, "#") == 0)
  {
    for (int i = 0; *str[0] != '\n' && *str[0] != ';'; ++i)
      *str = *str + 1;

    return (str);
  }

  return (NULL);
}

s_lexer                 *rec_lexer(char          *str,
                                   s_lexer       *lexer)
{
  char                  *first = NULL;
  int                   j = 0;
  int                   i = 0;
  s_lexer               *new_lex = NULL;

  first = calloc(1, sizeof (char));
  first = fill_first(str, &i, first);

  if (((j = is_token(str[i])) != -1) && i == 0)
  {
    first = realloc(first, ++i);
    first[i - 1] = str[i - 1];

    if (j > 6)
      first = ambi_token(str, &i, first);
  }

  if ((first = fn(&i, first)) && str[0] == '\0')
    return (aux(first, lexer));

  if (comment(first, &str) != NULL)
  {
    free(first);
    return (rec_lexer(str, lexer));
  }

  new_lex = the_function(str, first, new_lex, lexer);

  if (strcmp(first, "") == 0)
  {
    free(new_lex->token->id);
    free(lexer->token->id);
    free(new_lex->token);
    free(new_lex);
    free(first);
    return (rec_lexer(str + 1, lexer));
  }

  str = str + strlen(first);

  free(first);
  return (rec_lexer(str, new_lex));
}

void                    free_lexer(s_lexer	*lexer)
{
  s_lexer               *aux = NULL;

  if (lexer != NULL)
    lexer = lexer->head;

  while (lexer != NULL)
    {
      aux = lexer;
      lexer = lexer->next;
      free(aux->token->id);
      aux->token->id = NULL;
      free(aux->token);
      aux->token = NULL;
      free(aux);
      aux = NULL;
    }
}
